# -*- coding: UTF-8 -*-
# 作用: 生成C++头文件，记录可用于C++判断错误码是否触发诊断的依据

import os
import json
import enum
import typing

# 这个python文件所在路径
FOLDER_PATH = os.path.dirname(__file__)  # 替换为你的文件夹路径

# python错误码文件夹所在目录，目前应该在这个文件的上一层
ECODE_FOLDER_BASE_PATH = os.path.join(FOLDER_PATH, '../zuc/usr_intf/JAKAAPP/error_code')

ECODE_PATH_LIST = ['CONTROLLER', 'RIO_OR_EXTIO', 'SCB_OR_TOR_SENSOR', 'SERVO']

# 诊断状态位 key
DIAGNOSIS_KEY = U'isDiagnosis'

# 生成的错误码头文件路径
ECODE_HEADER_PATH = os.path.join(FOLDER_PATH, '.diagecode.h')

HEADER_COMMENT = '/* 根据错误码json文件, 调用脚本gen_ecode_header.py生成*/\n'

HEADER_MACRO_PREFIX = '''#ifndef DIAGECODE_H__
#define DIAGECODE_H__\n'''

HEADER_MACRO_SUFFIX = '''#endif // DIAGECODE_H__\n'''


class DiagEnum(enum.Enum):

    NO_DIAGNOSIS = 0  # 不触发诊断
    DIAGNOSIS = 1 # 触发诊断

    def __str__(self) -> str:
        # 覆盖默认的str调用， 转换Enum值为字符串
        if self == DiagEnum.NO_DIAGNOSIS:
            return "DiagnosisEnum::NO_DIAGNOSIS"
        else:
            return "DiagnosisEnum::DIAGNOSIS"


class Context(object):

    def __init__(self, fp):
        super(Context, self).__init__()
        # 生成的错误码头文件 handler
        # self.fp = fp
        self.ecode_map: typing.Dict[int, DiagEnum] = {}

    def add_ecode_item(self, errcode: int, diagEnum: DiagEnum):
        self.ecode_map[errcode] = diagEnum


def for_each_folder(folder_list, callback, ctx):
    for folder in folder_list:
        full_path = os.path.join(ECODE_FOLDER_BASE_PATH, folder)
        if os.path.exists(full_path):
            callback(full_path, ctx)
        else:
            print('Error! path {} does not exist.'.format(full_path))


def folder_callback(folder, ctx):
    files = os.listdir(folder)
    for_each_file(files, file_callback, folder, ctx)


def for_each_file(file_list, callback, folder, ctx):
    for filename in file_list:
        callback(filename, folder, ctx)


def file_callback(filename, folder, ctx: Context):
    '''
        根据文件名称设置是否诊断状态位
    '''

    strip_file_name = filename.strip()
    fullpath = os.path.join(folder, filename)
    if not strip_file_name.endswith('.json'):
        print('Info! Skip {}'.format(fullpath))
        return

    try:
        errcode = int(strip_file_name[:-5], 16)
    except ValueError:
        print("Error! failed to parse {}".format(filename))
        return

    if not os.path.exists(fullpath):
        print('Error! file {} no found.'.format(fullpath))

    fp = open(fullpath, 'r')
    json_data = json.load(fp)

    diagEnum = DiagEnum.NO_DIAGNOSIS if json_data[DIAGNOSIS_KEY] ==0 else DiagEnum.DIAGNOSIS;
    ctx.add_ecode_item(errcode, diagEnum)

    # ctx.fp.writelines([])

def write_ecode_pairs(fp, ctx):
    # 按errcode排序，避免每次生成的头文件不一致
    ecode_map: typing.Dict[int, DiagEnum] = dict(sorted(ctx.ecode_map.items(), key=lambda item: item[0]))
    for errcode, diagEnum in ecode_map.items():
        fp.writelines(['{' \
            + ('0x%08X' % errcode) + ',\t' \
            + (str(diagEnum)) \
            + '},\n'])

def main():
    print('== start gen diag ecode ==')
    with open(ECODE_HEADER_PATH, 'w') as fp:
        ctx = Context(fp)
        fp.writelines([HEADER_COMMENT, HEADER_MACRO_PREFIX])
        for_each_folder(ECODE_PATH_LIST, folder_callback, ctx)
        write_ecode_pairs(fp, ctx)
        fp.writelines([HEADER_MACRO_SUFFIX, HEADER_COMMENT])
    print('== finish gen diag ecode ==')


if __name__ == '__main__':
    main()
